package cn.com.captureNetPacket.util;


import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.PropertyAccessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.scheduling.annotation.Scheduled;

import com.fasterxml.jackson.databind.ObjectMapper;

import cn.com.captureNetPacket.CaptureNetPacketService;
import cn.com.captureNetPacket.model.RecordLog;
import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
public class RedisConfig {
	final static  String PREFIX="cnp:";
	final static String CLUSTER_GROUP="configClusterGroup";
	 private static ObjectMapper objMap= new ObjectMapper();
	 @Value("${spring.redis.model}")
	 private String model;
	 
	 @Value("${spring.redis.connectString}")
	 private String connectString;
	 
	 @Value("${spring.redis.master}")
	 private String master;
	    
	 
	 @Value("${spring.redis.password}")
	 private String password;
	 
	 @Value("${spring.redis.dbIndex}")
	 private int dbIndex;
	 
	 @Value("${spring.redis.pubChannel}")
	 private String pubChannel;
	 @Value("${spring.redis.clusterGroup}")
	 private String clusterGroup;
	 
	 
	 
	 private static  byte[] staticPubChannel;
	 
//	 @Value("${spring.redis.subProxyChannel}")
//	 private String subProxyChannel;
	 
	 
//	 @Value("${spring.redis.pubLeaderChannel}")
//	 private String pubLeaderChannel;
	 private static  boolean leader=true;
	 
	 
	 
	private int timeOut=60*1000;
	private long shutdownTimeOut=120*1000;
	 
	 private static RedisTemplate redisTemplate;
	private static StringRedisTemplate stringRedisTemp;
	private static LettuceConnectionFactory staticLettuceConnectionFactory;
	@Bean
	 public LettuceConnectionFactory redisConnectionFactory() throws UnsupportedEncodingException {
		staticPubChannel=pubChannel.getBytes();
		 RedisConfiguration redisConfiguration=null;
		 String ipPorts[]=connectString.split(",");
		 log.debug("-------------->connectString: {},model: {},master:{}",connectString,model,master);
		if(model.equalsIgnoreCase("cluster"))
		{
			//cluster
			Set hostNames=new HashSet<String>(Arrays.asList(ipPorts));
			redisConfiguration = new RedisClusterConfiguration(hostNames);
			
			
			if(password!=null && password.trim().length()>0)
			((RedisClusterConfiguration) redisConfiguration).setPassword(password);
			else
			((RedisClusterConfiguration) redisConfiguration).setPassword(RedisPassword.none());
		}
		else if(model.equalsIgnoreCase("sentinel"))
		{
			//sentinel
			Set hostNames=new HashSet<String>(Arrays.asList(ipPorts));
			redisConfiguration = new RedisSentinelConfiguration(master, hostNames);
			 
//			((RedisSentinelConfiguration) redisConfiguration).setDatabase(dbIndex);
			if(password!=null && password.trim().length()>0)
			((RedisSentinelConfiguration) redisConfiguration).setPassword(password);
			else
			((RedisSentinelConfiguration) redisConfiguration).setPassword(RedisPassword.none());
			
		}
		else {
			// standalone
			 String[] temp=ipPorts[0].split(":");
		   redisConfiguration = new  RedisStandaloneConfiguration(temp[0],Integer.parseInt(temp[1]));
//			((RedisStandaloneConfiguration) redisConfiguration).setDatabase(dbIndex);
			if(password!=null && password.trim().length()>0) {
			((RedisStandaloneConfiguration) redisConfiguration).setPassword(password);
//			log.debug("password:{}",password);
			}
			else 
				((RedisStandaloneConfiguration) redisConfiguration).setPassword(RedisPassword.none());
			}
     //根据配置和客户端配置创建连接
     LettuceConnectionFactory lettuceConnectionFactory = new   LettuceConnectionFactory(redisConfiguration);
     lettuceConnectionFactory.setDatabase(dbIndex);
     lettuceConnectionFactory.afterPropertiesSet();
     staticLettuceConnectionFactory=lettuceConnectionFactory;
     lettuceConnectionFactory.getConnection().subscribe(new RedisMessageListener(),pubChannel.getBytes());
//     lettuceConnectionFactory.getConnection().subscribe(new RedisProxyMessageListener(),subProxyChannel.getBytes());
	        return lettuceConnectionFactory;
	    }

	    @Bean
	    public RedisTemplate redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
	    	RedisTemplate redisTemp = new RedisTemplate<String, Object>();
	    	redisTemp.setConnectionFactory(redisConnectionFactory);
	    	Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
	    	
	  	  /**
	         * 使用 String 作为 Key 的序列化器,使用 Jackson 作为 Value 的序列化器
	         */
	        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//	        // key采用String的序列化方式
	        redisTemp.setKeySerializer(stringRedisSerializer);
//	        // hash的key也采用String的序列化方式
	        redisTemp.setHashKeySerializer(stringRedisSerializer);
//	        // value序列化方式采用jackson
	        redisTemp.setValueSerializer(jackson2JsonRedisSerializer);
//	        // hash的value序列化方式采用jackson
	        redisTemp.setHashValueSerializer(jackson2JsonRedisSerializer);
//	        stringRedisTemp=stringRedisTemplate;
	        redisTemplate=redisTemp;
	        return redisTemp;
	    }
	    
	    @Bean
	    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
	        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
	        stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
	        stringRedisTemp=stringRedisTemplate;
	        return stringRedisTemplate;
	    }
	 
	    
	    /**
	     * 
	    	* <strong>Title: 设置key<strong>
	    	* <p>Description: 设置超时12小时自动删除key <p>
	    	* <p>Company: </p> 
	    	*<strong>Copyright:</strong> Copyright (c) 2019
	    	* @version: 1.0
	    	* @author  ASUS:augustWei
	    	* @date  2020 上午2:23:09
	    	* @param key
	    	* @param value
	    	* @return
	     */
	    public  static boolean setValue(String key,String value) {
	    	try {
	    		stringRedisTemp.opsForValue().set(PREFIX+key, value,12,TimeUnit.HOURS);
	    	}catch (Exception e) {
	    		return false;
			}
			return true;
	    }
	    /**
	     * 
	    	* <strong>Title:设置key <strong>
	    	* <p>Description: 设置自定义时间key释放，微妙 <p>
	    	* <p>Company: </p> 
	    	*<strong>Copyright:</strong> Copyright (c) 2019
	    	* @version: 1.0
	    	* @author  ASUS:augustWei
	    	* @date  2020 上午2:23:00
	    	* @param key
	    	* @param value
	    	* @param timeOut
	    	* @return
	     */
	    public static boolean setValue(String key,String value,long timeOut) {
	    	try {
	    		stringRedisTemp.opsForValue().set(PREFIX+key, value,timeOut,TimeUnit.MILLISECONDS);
	    	}catch (Exception e) {
	    		return false;
	    	}
	    	return true;
	    }
	    /**
	     * 
	    	* <strong>Title: 设置key<strong>
	    	* <p>Description: 永久的 <p>
	    	* <p>Company: </p> 
	    	*<strong>Copyright:</strong> Copyright (c) 2019
	    	* @version: 1.0
	    	* @author  ASUS:augustWei
	    	* @date  2020 上午2:23:09
	    	* @param key
	    	* @param value
	    	* @return
	     */
	    public  static boolean setPermanentValue(String key,String value) {
	    	try {

	    		stringRedisTemp.opsForValue().set(PREFIX+key, value);
	    	}catch (Exception e) {
	    		return false;
	    	}
	    	return true;
	    }
	    /**
	     * 
	    	* <strong>Title: 获取key<strong>
	    	* <p>Description: 根据key获取字符串<p>
	    	* <p>Company: </p> 
	    	*<strong>Copyright:</strong> Copyright (c) 2019
	    	* @version: 1.0
	    	* @author  ASUS:augustWei
	    	* @date  2020 上午2:24:39
	    	* @param key
	    	* @return
	     */
	    public static String getValue(String key) {
	    	try {
	    		return stringRedisTemp.opsForValue().get(PREFIX+key).toString();
	    	}catch (Exception e) {
	    		return null;
	    	}
	    }
	    
	    public static Boolean deleteValue(String key) {
	    	try {
	    		return stringRedisTemp.delete(PREFIX+key);
	    	}catch (Exception e) {
	    		return null;
	    	}
	    }
	    public static Boolean deleteRealKeyValue(String key) {
	    	try {
	    		return stringRedisTemp.delete(key);
	    	}catch (Exception e) {
	    		return null;
	    	}
	    }
	    public static String getRealKeyValue(String key) {
	    	try {
	    		return stringRedisTemp.opsForValue().get(key).toString();
	    	}catch (Exception e) {
	    		return null;
	    	}
	    }
	    
	    public static Set<String> getkeys(String key) {
	    	try {
	    		return stringRedisTemp.keys(PREFIX+key+"*");
	    	}catch (Exception e) {
	    		return null;
	    	}
	    }
	    
	    /**
	     * 
	    	* <strong>Title: <strong>
	    	* <p>Description: 根据前缀获取key<p>
	    	* <p>Company: </p> 
	    	*<strong>Copyright:</strong> Copyright (c) 2019
	    	* @version: 1.0
	    	* @author  ASUS:augustWei
	    	* @date  2020 上午11:49:32
	    	* @param prefix
	    	* @param key
	    	* @return
	     */
	    public static String getValue(String prefix, String key) {
	    	try {
	    		log.debug("getValue   key: {}  ",prefix+key);
	    		return stringRedisTemp.opsForValue().get(prefix+key).toString();
	    	}catch (Exception e) {
	    		log.error("prefix: {}   key: {} 获取失败",prefix,key);
	    		return null;
	    	}
	    }
	    public static Set<String> getkeys(String prefix, String key) {
	    	try {
	    		log.debug("getValues   key: {}  ",prefix+key);
	    		return stringRedisTemp.keys(prefix+key+"*");
	    	}catch (Exception e) {
	    		log.error("prefix: {}   key: {} 获取失败",prefix,key);
	    		return null;
	    	}
	    }
	    
	    
	    
	    
	    public static void publishRecQueueMessage(String key,Object obj) {
	    	try {
	        	 if(redisTemplate.hasKey(PREFIX+key)) {
	        		 redisTemplate.opsForList().leftPush(PREFIX+key,obj);
	        	 }else {
	        		 redisTemplate.opsForList().leftPush(PREFIX+key,obj);
	        		 redisTemplate.expire(PREFIX+key, 24, TimeUnit.HOURS);
	        	 }
	    	}catch (Exception e) {
	    		log.error("prefix: {}   key: {} 获取失败",PREFIX,key);
	    	}
	    }
	    public static List<Object> subRecQueueMessage(String key) {
	    	List<Object> result=new ArrayList<Object>();
	    	 if(redisTemplate.hasKey(PREFIX+key)) {
	    		 long size=redisTemplate.opsForList().size(PREFIX+key);
	    		 for(int i=0;i<size;i++) {
	    			 result.add( redisTemplate.opsForList().rightPop(PREFIX+key));
	    		 }
	    	 }else {
	    		 return new ArrayList();
	    	 }
			return result;
	    
	    }
	    
	    
	    
	    
	    
	    
	    
	    
	    
	    
	    
	    /**
	     * 
	    	* <strong>Title: <strong>
	    	* <p>Description: 发布订阅消息<p>
	    	* <p>Company: </p> 
	    	*<strong>Copyright:</strong> Copyright (c) 2019
	    	* @version: 1.0
	    	* @author  ASUS:augustWei
	    	* @date  2020 上午3:43:51
	    	* @param message
	    	* @return
	     */
	    public  static int publishMessage(String messType,Object message) {
			long clientRecivenumber=-1;
	    	try {
	    		Map messTemp=new HashMap<String, Object>();
	    		messTemp.put("messType", messType);
	    		messTemp.put("payload", message);

				clientRecivenumber=staticLettuceConnectionFactory.getConnection().publish(staticPubChannel, Tools.getjsonString(messTemp).getBytes("UTF-8"));
				log.debug("{}类型的消息：《{}》 已有客户{}收到。",messType,message,clientRecivenumber);
	    	} catch (UnsupportedEncodingException e) {
				return 0;
			}
			return (int) clientRecivenumber;
	    	
	    }
	    @Scheduled(fixedRate = 10000)
	    public void publishLeaderMessage() throws UnsupportedEncodingException {
//	    	log.debug("发布到通道------------------------------------>>>>>{}",pubChannel);
	    	String cnpClusterValue=null;
	    	cnpClusterValue=getValue(CLUSTER_GROUP+":"+clusterGroup);
	    	if(cnpClusterValue!=null) {
	    		if(cnpClusterValue.equals(CaptureNetPacketService.getClusterServId())) {
	    			// 延时选举为主
	    			setValue(CLUSTER_GROUP+":"+clusterGroup, CaptureNetPacketService.getClusterServId(), 15000);
	    		}else {
	    			leader=false;
	    		}
	    	}else {
	    		setValue(CLUSTER_GROUP+":"+clusterGroup, CaptureNetPacketService.getClusterServId(), 15000);
	    		leader=true;
	    	}
	    	 
	    }
	    
	    
	    public static boolean  isLeader() {
	    	return leader;
	    }
	    
}
